##Replication code for "A Constitution I am Used To? 
##Constitutional Endurance and Replacement in Democratic Latin America"

#Set R’s working directory to where the files are
setwd("~/2022-0079")

#Install Packages
if(require(here) == F) {install.packages("here"); require(here)}
if(require(QCA) == F) {install.packages("QCA"); require(QCA)}
if(require(tidyverse) == F) {install.packages("tidyverse"); require(tidyverse)}
if(require(SetMethods) == F) {install.packages("SetMethods"); require(SetMethods)}

#load
library(here)
library(QCA)
library(tidyverse)
library(SetMethods)

data <- readr::read_csv2(here("ABCP_Const_Dataset.csv")) %>%
        mutate(powersharing_alt = as.numeric(powersharing_alt)) %>%
        mutate(mobilization_alt = as.numeric(mobilization_alt)) %>%
        mutate(result = as.numeric(result)) %>%
        mutate(autoconst = as.numeric(autoconst)) %>%
        select(-"...1", -"...2") %>%
        mutate(result = case_when(country == "Chile" ~ 1,
                                   T ~ result)) %>%
        mutate(country = case_when(country == "Argentina" ~ "AR",
                                   country == "Bolivia" ~ "BO",
                                   country == "Brazil" ~ "BR",
                                   country == "Chile" ~ "CL",
                                   country == "Costa Rica" ~ "CR",
                                   country == "Colombia" ~ "CO",
                                   country == "Dominican Republic" ~ "DO",
                                   country == "Ecuador" ~ "EC",
                                   country == "El Salvador" ~ "SV",
                                   country == "Guatemala" ~ "GT",
                                   country == "Honduras" ~ "HN",
                                   country == "Mexico" ~ "MX",
                                   country == "Nicaragua" ~ "NI",
                                   country == "Panama" ~ "PA",
                                   country == "Paraguay" ~ "PY",
                                   country == "Peru" ~ "PE",
                                   country == "Uruguay" ~ "UY",
                                   country == "Venezuela" ~ "VE"))

##Data Wrangling----
##Setting up "Amendment" condition
amend <- data %>%
         select(country, amndapct_median, adjudication_median, rights) %>%
         arrange(desc(amndapct_median)) %>%
         #proportion of the vote  needed to approve a constitutional amendment, where <= 2 is 3/5 or below
         #and > 2 is above 3/5 of the parliament
         mutate(rigity1 = case_when(amndapct_median <= 2 ~ 1,
                                    amndapct_median > 2 ~ 0)) %>%
         #Ríos-Figueroa's (2011) Power Index of Constitutional Judges, which goes from 0 to 8. 
         #In a few words, the index takes into account the degree to which judges can exert constitutional
         #review
         mutate(rigity2 = case_when(adjudication_median >= 3 ~ 1,
                                    adjudication_median < 3 ~ 0)) %>%
         ##Aggregating into a single set
         mutate(amendment = rigity1 + rigity2) %>%
         select(country, amendment)

leftover <- data %>%
            select(country, powersharing_alt, mobilization_alt, legacy_alt2, autoconst, rights, result) %>%
            left_join(amend) 

leftover <- column_to_rownames(leftover, var = "country")

##Excluding Dominican Republic from the dataset
leftover <- leftover[-7,]

##Calibration Process----
##These are the steps to implement the calibration process outlined in Table 2
##calibration
#POS - "natural" gap in the data
findTh(leftover$powersharing_alt, n = 1)
leftover$powersharing_alt<- calibrate(leftover$powersharing_alt, type = "crisp", thresholds = 0.742132)

#Legacy 
leftover$legacy_alt2 <- calibrate(leftover$legacy_alt2, type = "crisp", thresholds = 13)

#MOB - Qualitative / Direct Assignment based on the Chilean case
leftover$mobilization_alt<- calibrate(leftover$mobilization_alt, type = "crisp", thresholds = "1.8675161")

#Amendments - Sever: easy or difficult to amend?
leftover$amendment <- calibrate(leftover$amendment, type = "crisp", thresholds = 2)

#Aut. Const - Sever: Does the constitution stem from the authoritarian period?

#Rights - "natural" gap in the data
leftover$rights <- calibrate(leftover$rights, type = "crisp", thresholds = 48)

leftover_calibrated <- leftover %>%
                       select(powersharing_alt, amendment, legacy_alt2, mobilization_alt, rights, autoconst, result) %>%
                       rename(POS = powersharing_alt,
                              AME = amendment,
                              LEG = legacy_alt2,
                              MOB = mobilization_alt,
                              RIG = rights,
                              ACO = autoconst,
                              OUT = result)

##Analyses----
#Analysis of Necessity for the outcome
#The code below renders Table 3
superSubset(leftover_calibrated, 
            outcome = "OUT",
            incl.cut = 0.9,
            ron.cut = 0.6)

#Complete Analysis of Necessity - Table A.1 in the Supplementary Material
QCAfit(x = leftover_calibrated[,c("POS", "AME", "LEG", "MOB" , "RIG", "ACO")],
       y = leftover_calibrated$OUT)

#Checking for Deviant Cases in Kind
#Table A.2 in the Supplementary Material
sol <- "RIG"

XYplot(sol, "OUT" , data = leftover_calibrated, enhance = T, relation = "necessity", jitter = T, 
       xlab = "RIG", ylab = "OUT", clabels = rownames(leftover_calibrated),
       family = "regular",
       cex = 1)

#Table A.3 in the Supplementary Material
sol1 <- "AME + ~LEG"

XYplot(sol1, "OUT" , data = leftover_calibrated, enhance = T, relation = "necessity", jitter = T, 
       xlab = "AME + ~LEG", ylab = "OUT", clabels = rownames(leftover_calibrated),
       family = "regular",
       cex = 1)

#Table A.4 in the Supplementary Material
sol3 <- "~LEG + ~ACO"

XYplot(sol3, "OUT" , data = leftover_calibrated, enhance = T, relation = "necessity", jitter = T, 
       xlab = "~LEG + ~ACO", ylab = "OUT", clabels = rownames(leftover_calibrated),
       family = "regular",
       cex = 1)

##TT for the outcome
TTleftover <- truthTable(leftover_calibrated, outcome = "OUT",
                         complete = TRUE, incl.cut = 0.8,
                         sort.by = "incl, n+",
                         show.cases = TRUE)

##Excluding remainders that violate the necessity statement
ESA <- findRows("~RIG", TTleftover)

##Sufficient analysis for the outcome
#The code below renders Table 5 in the Main Text
intermediate_result <- minimize(TTleftover, include = "?", details = TRUE, dir.exp = "1, 1, 0, 0, 0, 1", exclude =  ESA) 

#The code below renders Table A.5 in the Supplementary Material
conservative_result <- minimize(TTleftover, details = TRUE) 

#The code below renders Table A.6 in the Supplementary Material
parsimonious_result <- minimize(TTleftover, include = "?", details = TRUE, exclude =  ESA)

#The code below displays the results in LaTeX format
stargazerSol(conservative_result, type = "latex", sol = 1, outcome = "OUT", show.cases = T)
stargazerSol(parsimonious_result, type = "latex", sol = 1, outcome = "OUT", show.cases = T)


##Necessity test for the non-outcome
#The code below renders Table A.7 in the Supplementary Material
superSubset(leftover_calibrated,
            outcome = "~OUT",
            incl.cut = 0.9,
            ron.cut = 0.6)

lo2 <- leftover_calibrated %>%
       mutate(out = case_when(OUT == 1 ~ 0,
                              OUT == 0 ~ 1))

#Complete Analysis of Necessity
#Table A.8 in the Supplementary Material
QCAfit(x = lo2[,c("POS", "AME", "LEG", "MOB" , "RIG", "ACO")],
       y = lo2$out)

#Checking for Deviant Cases in Kind
#Table A. 9
sol4 <- "LEG + ~RIG"

XYplot(sol4, "~OUT" , data = leftover_calibrated, enhance = T, relation = "necessity", jitter = T, 
       xlab = "LEG + ~RIG", ylab = "~OUT", clabels = rownames(leftover_calibrated),
       family = "regular",
       cex = 1)

##TT for the non-outcome
NTTleftover <- truthTable(leftover_calibrated, outcome = "~OUT",
                         complete = TRUE, incl.cut = 0.8,
                         sort.by = "incl, n+",
                         show.cases = TRUE)

ESA2 <- findRows("~LEG * RIG", NTTleftover)


##Sufficient analysis for the non-outcome
#The code below renders the results for the non-outcome based on the intermediate solution (not shown in the main files, but reproducible here)
intermediate_result_no <- minimize(NTTleftover, include = "?", details = TRUE, dir.exp = "0, 0, 1, 1, 1, 0", exclude = ESA2)

#The code below renders Table A.11 in the Supplementary Material
conservative_result_no <- minimize(NTTleftover, details = TRUE) 

#The code below renders Table A.12 in the Supplementary Material
parsimonious_result_no <- minimize(NTTleftover, include = "?", details = TRUE, exclude = ESA2) 


#LaTeX format of the above results
stargazerSol(conservative_result_no, type = "latex", sol = 1, outcome = "~OUT", show.cases = T)
stargazerSol(parsimonious_result_no, type = "latex", sol = 1, outcome = "~OUT", show.cases = T)


##Robustness Tests - 1st----
##Changing Case Selection
##Note that the Dominican Republican now makes part of the analyses,
##and Chile is a case of constitutional replacement.
##The procedures are the same as the above, except for the change in the cases included in the analyses

#Cleaning the environment to kick in the robustness test
#Be aware that this is going to erase all of your variables in your environment
#If you don't want to lose anything specifically, PLEASE DO NOT RUN THE CODE BELOW
rm(list = ls())

data <- readr::read_csv2(here("ABCP_Const_Dataset.csv")) %>%
        mutate(powersharing_alt = as.numeric(powersharing_alt)) %>%
        mutate(mobilization_alt = as.numeric(mobilization_alt)) %>%
        mutate(result = as.numeric(result)) %>%
        mutate(autoconst = as.numeric(autoconst)) %>%
        select(-"...1", -"...2") %>%
        mutate(result = case_when(country == "Chile" ~ 0,
                                  T ~ result)) %>%
        mutate(country = case_when(country == "Argentina" ~ "AR",
                                   country == "Bolivia" ~ "BO",
                                   country == "Brazil" ~ "BR",
                                   country == "Chile" ~ "CL",
                                   country == "Costa Rica" ~ "CR",
                                   country == "Colombia" ~ "CO",
                                   country == "Dominican Republic" ~ "DO",
                                   country == "Ecuador" ~ "EC",
                                   country == "El Salvador" ~ "SV",
                                   country == "Guatemala" ~ "GT",
                                   country == "Honduras" ~ "HN",
                                   country == "Mexico" ~ "MX",
                                   country == "Nicaragua" ~ "NI",
                                   country == "Panama" ~ "PA",
                                   country == "Paraguay" ~ "PY",
                                   country == "Peru" ~ "PE",
                                   country == "Uruguay" ~ "UY",
                                   country == "Venezuela" ~ "VE"))

amend <- data %>%
         select(country, amndapct_median, adjudication_median, rights) %>%
         arrange(desc(amndapct_median)) %>%
         #proportion of the vote  needed to approve a constitutional amendment, where <= 2 is 3/5 or below
         #and > 2 is above 3/5 of the parliament
         mutate(rigity1 = case_when(amndapct_median <= 2 ~ 1,
                                    amndapct_median > 2 ~ 0)) %>%
         #Ríos-Figueroa's (2011) Power Index of Constitutional Judges, which goes from 0 to 8. 
         #In a few words, the index takes into account the degree to which judges can exert constitutional
         #review
         mutate(rigity2 = case_when(adjudication_median >= 3 ~ 1,
                                    adjudication_median < 3 ~ 0)) %>%
         ##Aggregating into a single set
         mutate(amendment = rigity1 + rigity2) %>%
         select(country, amendment)

leftover <- data %>%
            select(country, powersharing_alt, mobilization_alt, legacy_alt2, autoconst, rights, result) %>%
            left_join(amend) 

leftover <- column_to_rownames(leftover, var = "country")

#POS - "natural" gap in the data
findTh(leftover$powersharing_alt, n = 1)
leftover$powersharing_alt<- calibrate(leftover$powersharing_alt, type = "crisp", thresholds = 0.742132)

#Legacy 
leftover$legacy_alt2 <- calibrate(leftover$legacy_alt2, type = "crisp", thresholds = 13)

#MOB - Qualitative / Direct Assignment based on the Chilean case
leftover$mobilization_alt<- calibrate(leftover$mobilization_alt, type = "crisp", thresholds = "1.8675161")

#Amendments - Sever: easy or difficult to amend?
leftover$amendment <- calibrate(leftover$amendment, type = "crisp", thresholds = 2)

#Aut. Const - Sever: Does the constitution stem from the authoritarian period?

#Rights - "natural" gap in the data
leftover$rights <- calibrate(leftover$rights, type = "crisp", thresholds = 48)

leftover_calibrated <- leftover %>%
  select(powersharing_alt, amendment, legacy_alt2, mobilization_alt, rights, autoconst, result) %>%
  rename(POS = powersharing_alt,
         AME = amendment,
         LEG = legacy_alt2,
         MOB = mobilization_alt,
         RIG = rights,
         ACO = autoconst,
         OUT = result)

superSubset(leftover_calibrated, 
            outcome = "OUT",
            incl.cut = 0.9,
            ron.cut = 0.6)

#Complete Analysis of Necessity
QCAfit(x = leftover_calibrated[,c("POS", "AME", "LEG", "MOB" , "RIG", "ACO")],
       y = leftover_calibrated$OUT)

#Checking for Deviant Cases in Kind
sol <- "RIG"

XYplot(sol, "OUT" , data = leftover_calibrated, enhance = T, relation = "necessity", jitter = T, 
       xlab = "RIG", ylab = "OUT", clabels = rownames(leftover_calibrated),
       family = "regular",
       cex = 1)

sol1 <- "AME + ~LEG"

XYplot(sol1, "OUT" , data = leftover_calibrated, enhance = T, relation = "necessity", jitter = T, 
       xlab = "AME + ~LEG", ylab = "OUT", clabels = rownames(leftover_calibrated),
       family = "regular",
       cex = 1)

##TT for the outcome
TTleftover <- truthTable(leftover_calibrated, outcome = "OUT",
                         complete = TRUE, incl.cut = 0.8,
                         sort.by = "incl, n+",
                         show.cases = TRUE)

##Excluding remainders that violate the necessity statement
ESA <- findRows(TTleftover, "~RIG")

##Sufficient analysis for the outcome
##The code below renders the findings of Table A.13 in the Supplementary Material
intermediate_result <- minimize(TTleftover, include = "?", details = TRUE, dir.exp = "1, 1, 0, 0, 0, 1", exclude =  ESA) #Table A.13
stargazerSol(intermediate_result, type = "latex", sol = 1, outcome = "OUT", show.cases = T)



##Analysis for the non-outcome
superSubset(leftover_calibrated, 
            outcome = "~OUT",
            incl.cut = 0.9,
            ron.cut = 0.6)

lo2 <- leftover_calibrated %>%
  mutate(out = case_when(OUT == 1 ~ 0,
                         OUT == 0 ~ 1))

#Complete Analysis of Necessity
QCAfit(x = lo2[,c("POS", "AME", "LEG", "MOB" , "RIG", "ACO")],
       y = lo2$out)

#Checking for Deviant Cases in Kind
sol4 <- "LEG + ~RIG"

XYplot(sol4, "~OUT" , data = leftover_calibrated, enhance = T, relation = "necessity", jitter = T, 
       xlab = "LEG + ~RIG", ylab = "~OUT", clabels = rownames(leftover_calibrated),
       family = "regular",
       cex = 1)

##TT for the non-outcome
NTTleftover <- truthTable(leftover_calibrated, outcome = "~OUT",
                          complete = TRUE, incl.cut = 0.8,
                          sort.by = "incl, n+",
                          show.cases = TRUE)

ESA2 <- findRows(NTTleftover, "~LEG * RIG")


##Sufficient analysis for the non-outcome
##The code below renders the findings of Table A.14 in the Supplementary Material
intermediate_result_no <- minimize(NTTleftover, include = "?", details = TRUE, dir.exp = "0, 0, 1, 1, 1, 0", exclude = ESA2) #Table A.14
stargazerSol(intermediate_result_no, type = "latex", sol = 1, outcome = "OUT", show.cases = T)

##Robustness Tests - 2nd----
##Now, we test the calibration process of our conditions
##Note that the only difference from the code below is the change in the cut-offs to belonging or not in a given set
##Everything else remains the same. 

#Cleaning the environment to kick in the robustness test
#Be aware that this is going to erase all of your variables in your environment
#If you don't want to lose anything specifically, PLEASE DO NOT RUN THE CODE BELOW
rm(list = ls())


data <- readr::read_csv2(here("ABCP_Const_Dataset.csv")) %>%
  mutate(powersharing_alt = as.numeric(powersharing_alt)) %>%
  mutate(mobilization_alt = as.numeric(mobilization_alt)) %>%
  mutate(result = as.numeric(result)) %>%
  mutate(autoconst = as.numeric(autoconst)) %>%
  select(-"...1", -"...2") %>%
  mutate(result = case_when(country == "Chile" ~ 1,
                            T ~ result)) %>%
  mutate(country = case_when(country == "Argentina" ~ "AR",
                             country == "Bolivia" ~ "BO",
                             country == "Brazil" ~ "BR",
                             country == "Chile" ~ "CL",
                             country == "Costa Rica" ~ "CR",
                             country == "Colombia" ~ "CO",
                             country == "Dominican Republic" ~ "DO",
                             country == "Ecuador" ~ "EC",
                             country == "El Salvador" ~ "SV",
                             country == "Guatemala" ~ "GT",
                             country == "Honduras" ~ "HN",
                             country == "Mexico" ~ "MX",
                             country == "Nicaragua" ~ "NI",
                             country == "Panama" ~ "PA",
                             country == "Paraguay" ~ "PY",
                             country == "Peru" ~ "PE",
                             country == "Uruguay" ~ "UY",
                             country == "Venezuela" ~ "VE"))

amend <- data %>%
  select(country, amndapct_median, adjudication_median, rights) %>%
  arrange(desc(amndapct_median)) %>%
  #proportion of the vote  needed to approve a constitutional amendment, where <= 2 is 3/5 or below
  #and > 2 is above 3/5 of the parliament
  mutate(rigity1 = case_when(amndapct_median <= 2 ~ 1,
                             amndapct_median > 2 ~ 0)) %>%
  #Ríos-Figueroa's (2011) Power Index of Constitutional Judges, which goes from 0 to 8. 
  #In a few words, the index takes into account the degree to which judges can exert constitutional
  #review
  mutate(rigity2 = case_when(adjudication_median >= 3 ~ 1,
                             adjudication_median < 3 ~ 0)) %>%
  ##Aggregating into a single set
  mutate(amendment = rigity1 + rigity2) %>%
  select(country, amendment)

leftover <- data %>%
  select(country, powersharing_alt, mobilization_alt, legacy_alt2, autoconst, rights, result) %>%
  left_join(amend) 

leftover <- column_to_rownames(leftover, var = "country")

##Excluding Dominican Republic from the dataset
leftover <- leftover[-7,]

##calibration
#POS - "natural" gap in the data
findTh(leftover$powersharing_alt, n = 1)
leftover$powersharing_alt<- calibrate(leftover$powersharing_alt, type = "crisp", thresholds = 0.742132)

#Legacy 
leftover$legacy_alt2 <- calibrate(leftover$legacy_alt2, type = "crisp", thresholds = 15)

#MOB - Qualitative / Direct Assignment based on the Chilean case
leftover$mobilization_alt<- calibrate(leftover$mobilization_alt, type = "crisp", thresholds = 2.0)

#Amendments - Sever: easy or difficult to amend?
leftover$amendment <- calibrate(leftover$amendment, type = "crisp", thresholds = 2)

#Aut. Const - Sever: Does the constitution stem from the authoritarian period?

#Rights - "natural" gap in the data
leftover$rights <- calibrate(leftover$rights, type = "crisp", thresholds = 46)

leftover_calibrated <- leftover %>%
  select(powersharing_alt, amendment, legacy_alt2, mobilization_alt, rights, autoconst, result) %>%
  rename(POS = powersharing_alt,
         AME = amendment,
         LEG = legacy_alt2,
         MOB = mobilization_alt,
         RIG = rights,
         ACO = autoconst,
         OUT = result)

#Analysis of Necessity for the outcome
superSubset(leftover_calibrated, 
            outcome = "OUT",
            incl.cut = 0.9,
            ron.cut = 0.6)

#Complete Analysis of Necessity
QCAfit(x = leftover_calibrated[,c("POS", "AME", "LEG", "MOB" , "RIG", "ACO")],
       y = leftover_calibrated$OUT)

##TT for the outcome
TTleftover <- truthTable(leftover_calibrated, outcome = "OUT",
                         complete = TRUE, incl.cut = 0.8,
                         sort.by = "incl, n+",
                         show.cases = TRUE)

##Excluding remainders that violate the necessity statement
ESA <- findRows(TTleftover, "~RIG")

##Sufficient analysis for the outcome
##The code below renders the findings of both Table A.15 and A.16 in the Supplementary Material
intermediate_result <- minimize(TTleftover, include = "?", details = TRUE, dir.exp = "1, 1, 0, 0, 0, 1", exclude =  ESA) 

stargazerSol(intermediate_result, type = "latex", sol = 1, outcome = "OUT", show.cases = T)

##Necessity test for the non-outcome
superSubset(leftover_calibrated, 
            outcome = "~OUT",
            incl.cut = 0.9,
            ron.cut = 0.6)

lo2 <- leftover_calibrated %>%
  mutate(out = case_when(OUT == 1 ~ 0,
                         OUT == 0 ~ 1))

#Complete Analysis of Necessity
QCAfit(x = lo2[,c("POS", "AME", "LEG", "MOB" , "RIG", "ACO")],
       y = lo2$out)

#Checking for Deviant Cases in Kind
sol4 <- "LEG + ~RIG"

XYplot(sol4, "~OUT" , data = leftover_calibrated, enhance = T, relation = "necessity", jitter = T, 
       xlab = "LEG + ~RIG", ylab = "~OUT", clabels = rownames(leftover_calibrated),
       family = "regular",
       cex = 1)

##TT for the non-outcome
NTTleftover <- truthTable(leftover_calibrated, outcome = "~OUT",
                          complete = TRUE, incl.cut = 0.8,
                          sort.by = "incl, n+",
                          show.cases = TRUE)

ESA2 <- findRows(NTTleftover, "~LEG * RIG")


##Sufficient analysis for the non-outcome
##The code below renders the findings of both Table A.17 and A.18 in the Supplementary Material
intermediate_result_no <- minimize(NTTleftover, include = "?", details = TRUE, dir.exp = "0, 0, 1, 1, 1, 0", exclude = ESA2) 

stargazerSol(intermediate_result_no, type = "latex", sol = 1, outcome = "~OUT", show.cases = T)

